#include <tft_lcd.h>
#include <stdint.h>
#include <pronano.h>
//#include <screen_page.h>
#include <measurement.h>
#include <UDC.h>

int extint0_count = 0;
volatile int8_t User_key = Null_key, lock_key_queue = 0, head_key = -1, tail_key = -1, key_queue[MAX_keys];
extern volatile uint8_t bPrinter_status;
volatile uint32_t refresh_time = 0;
#ifdef Dump_Dvalid_CNR_DEBUG
double Data_Valid_CNR[100];
#endif  //Dump_Dvalid_CNR_DEBUG
volatile uint8_t g_u8IsPrepareFAT = 0;
extern volatile uint8_t g_u8IsUsbPlugin;
extern const unsigned char g_Screen_Saving_page[][12], g_Msg_page[][12], gMain_menu_page[][12];
#ifdef LOCCUS_ODM
int screen_saving_X = 160;
int screen_saving_Y = 24;
#elif defined TIANGEN_ODM
int screen_saving_X = 128;
int screen_saving_Y = 32;
#elif  defined KASVI_ODM
int screen_saving_X = 128;
int screen_saving_Y = 40;
#else
int screen_saving_X = 80;
int screen_saving_Y = 48;
#endif

/*20130419 added by michael
dequeue the key queue*/
char Get_key_queue(int enable_screen_saving) {
	int circle_x, circle_y, i = 0;
	char key = Null_key;

  while (lock_key_queue)
    Delay100ms(1);
  lock_key_queue = 1;
  if (head_key==-1)
    key = Null_key;
  else {
	 if (head_key < tail_key) {
	   key = key_queue[head_key++];
//	   printf("1.  get key: %d, head_key: %d\n", key,  head_key-1);
	 }
	 else
        if (head_key > tail_key) {
		  key = key_queue[head_key++];
		  if (head_key==MAX_keys)
		     head_key = 0;
		}

	 if (head_key==tail_key) {
	    //key = Null_key;
        head_key = tail_key = -1;
	 }
  }

  lock_key_queue = 0;

  if (enable_screen_saving==1) {
  
  }

  if (enable_screen_saving==1 && g_u8IsUsbPlugin && !(g_u8UsbState&USB_STATE_FLAG_SUSPENDED)) {
	  TFT_Send_Command(g_Msg_page[52], 12, 0);  //USB logo
	  TFT_Send_Command(g_Msg_page[52], 12, 0);  //USB logo
	  while (g_u8IsUsbPlugin && !(g_u8UsbState&USB_STATE_FLAG_SUSPENDED)) {
		  //printf("USB attach\n");
		  //UsbIsr();
		  //printf("g_u8IsUsbPlugin: %x, g_u8UsbState: %x\n", g_u8IsUsbPlugin, g_u8UsbState);
		  Delay100ms(5);
	  }
	  TFT_Send_Command(gMain_menu_page[0], 12, 0);  //background
	  Put_key_Queue(Refresh_key);
	  g_u8IsPrepareFAT = 0;
  }

  if (key==Null_key) {
#if (!defined(DEF_ODM) && !defined(TIANGEN_ODM) && !defined(LOCCUS_ODM) && !defined(KASVI_ODM)) || (defined(DEF_ODM) && (defined(TIANGEN_ODM) || defined(LOCCUS_ODM) || defined(KASVI_ODM)))
#if 1
	  if (DrvTIMER_GetTicks(TMR2) > Timeout_Screen_Saving && enable_screen_saving==1)
		  TFT_Send_Command(g_Screen_Saving_page[0], 12, 0);  //white background
	  while (DrvTIMER_GetTicks(TMR2) > Timeout_Screen_Saving && enable_screen_saving==1 && (!g_u8IsUsbPlugin || (g_u8UsbState&USB_STATE_FLAG_SUSPENDED))) {
		  circle_x = rand() % (320-screen_saving_X);
		  circle_y = rand() % (240-screen_saving_Y);
		  circle_x = 8 * (circle_x / 8);
		  //Show_LCD_IMG(g_Screen_Saving_page, 1, circle_x, circle_y);  //small logo
		  memcpy(buf2, g_Screen_Saving_page[1], 12);
		  buf2[4] = (circle_x & 0xff00) >> 8;
		  buf2[5] = circle_x & 0x00ff;
		  buf2[6] = 0x00;
		  buf2[7] = circle_y;
		  for (i = 2, buf2[10] = 0; i < 10; i++)
			  buf2[10] += buf2[i];
		  TFT_Send_Command(buf2, 12, 0);  //small logo
		  Delay100ms(8);
		  TFT_Send_Command(g_Screen_Saving_page[0], 12, 0);  //white background
		  key = Refresh_key;
	  }
#endif
#endif
  }

  return key;
}

/*20130419 added by michael
enqueue the key queue*/
void Put_key_Queue(char key) {
  //while (lock_key_queue)
    //Delay100ms(1);
  lock_key_queue = 1;
  if (head_key==-1 || tail_key==head_key) {
    head_key = 0;
	tail_key = 1;
	key_queue[head_key] = key;
  }
  else {
	 if (head_key < tail_key) {
	   key_queue[tail_key++] = key;
//key enqueue to reach the end, after tail_key reach MAX_keys, tail_key less than head_key
	   if (tail_key==MAX_keys) {
         tail_key = 0;
		 if (head_key==tail_key)
		   head_key++;
	   }
	 }
	 else	  
//key dequeue to reach the  end, after head_key equal MAX_keys, head_key < tail_key again
			if (head_key > tail_key) {
			  key_queue[tail_key++] = key;
			  if (tail_key==head_key) {
			    head_key++;
				if (head_key==MAX_keys)
				   head_key = 0;
			  }
			  /*if (tail_key==MAX_keys) {
			    head_key = 1;
				tail_key = 0;
			  }*/
			}
  }
  lock_key_queue = 0;
}

//PB.9/SS11/TM1, PB.14/INT0, PB.13/CPO1 interrupt event callback
void GPABCallback(uint32_t u32GpaStatus, uint32_t u32GpbStatus) {
  int i = 0;
  volatile double cur_Dvalid_CNR = 0;
  static int knight = 0;

#ifdef SYS_DEBUG
  //printf("GPAB Interrupt! GPA:0x%04x  GPB:0x%04x\n", u32GpaStatus, u32GpbStatus);
#endif  //SYS_DEBUG

#ifdef USE_KEY_QUEUE
  if (u32GpbStatus & (1<<9))  //up_key
  {
    if (DrvTIMER_GetTicks(TMR2) <= Timeout_Screen_Saving)
      Put_key_Queue(Up_key);
	 DrvTIMER_ResetTicks(TMR2);
#ifdef SYS_DEBUG
	 printf("up_key current tick: %d\n", DrvTIMER_GetTicks(TMR2));
#endif  //SYS_DEBUG
	 //  DrvTIMER_Ioctl(TMR2, TIMER_IOC_ENABLE_INT, 0);
  }
  else
        if (u32GpbStatus & (1<<13))  //enter_key
		{
		  if (DrvTIMER_GetTicks(TMR2) <= Timeout_Screen_Saving)
            Put_key_Queue(Enter_key);
		  DrvTIMER_ResetTicks(TMR2);
#ifdef SYS_DEBUG																							   
		  printf("enter_key current tick: %d\n", DrvTIMER_GetTicks(TMR2));
#endif  //SYS_DEBUG
		  //DrvTIMER_Ioctl(TMR2, TIMER_IOC_ENABLE_INT, 0);
		}
//        else
//           Put_key_Queue(Null_key);
#else  //USE_KEY_QUEUE
  if (u32GpbStatus & (1<<9))  //up_key
	User_key = Up_key;
  else
        if (u32GpbStatus & (1<<13))  //enter_key
          User_key = Enter_key;
        else
 	       User_key = Null_key;
#endif  //USE_KEY_QUEUE


#ifndef Measure_test_mode
/*20130502 added by michael*/
  if ((u32GpaStatus & 0x2000) && (adc_data_ready < (Measure_times+throw_samples))) {
    cur_Dvalid_CNR = DrvPWM_GetTimerCounter(DRVPWM_TIMER0) ;
#ifdef Dump_Dvalid_CNR_DEBUG
	Data_Valid_CNR[knight++] = cur_Dvalid_CNR;
	if (knight%100==0)
	  for (i = 0; i <  knight && i < 100; i++)
	     printf("index: %d, CNR: %lf\n", i, Data_Valid_CNR[i]);
	if (knight==100)
	  knight = 0;
#endif  //#ifdef Dump_Dvalid_CNR_DEBUG
	//printf("cur_Xenon_PWM_CNR: %lf, %lf, %lf, %lf, %lf %d\n", cur_Dvalid_CNR, 	Start_Dvalid_CNR1, Stop_Dvalid_CNR1, Start_Dvalid_CNR2, Stop_Dvalid_CNR2, knight++);
	//printf("%d\n", count1);
    if ((cur_Dvalid_CNR < Start_Dvalid_CNR1 && cur_Dvalid_CNR > Stop_Dvalid_CNR1) || (cur_Dvalid_CNR < Start_Dvalid_CNR2 && cur_Dvalid_CNR > Stop_Dvalid_CNR2)) {
//    adc_data_ready++;
#ifdef DDC114_DEBUG
	outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->PIN) ^ (1 << 11));
#endif
    }
	else {
	   redundancy_entry++;
#ifdef Dump_Dvalid_CNR_DEBUG
	   if ((knight-1) < 0)
         knight = 99;
	   else
	      knight--;
	   printf("redundancy index: %d, CNR: %lf\n", knight, cur_Dvalid_CNR);
#endif  //#ifdef Dump_Dvalid_CNR_DEBUG
       
	   return;
	}

    //if (adc_data_ready >= throw_samples) {
      do
      {
        SPI1->CNTRL.GO_BUSY = 1;
        while (SPI1->CNTRL.GO_BUSY);
		switch (i) {
		  case 0:
			  adc_temp = SPI1->RX[0];
		      break;
		  case 1:
		      adc_temp = SPI1->RX[0];
		      break;
		  case 2:
		      adc_temp = SPI1->RX[0];
			  break;
		  case 3:
		      adc_temp = SPI1->RX[0];
			  if (adc_data_ready >= throw_samples) {
				  adc_data[cur_phase][adc_data_ready-throw_samples] = SPI1->RX[0];
				  if (cur_phase && adc_data[cur_phase][adc_data_ready-throw_samples] < 100) {
					  zero_count++;
					  //printf("%d\n", zero_count);
				  }
				  //else
					  adc_data_ready++;
			  }
			  else
				  adc_data_ready++;
		      break;
		}
        i++;
      } while (i < 4);
	/*}
	else
	    adc_data_ready++;*/
  }
#endif
}

//PC.0/SS01/I2SLRCLK interrupt event callback
void GPCDECallback(uint32_t u32GpcStatus, uint32_t u32GpdStatus, uint32_t u32GpeStatus) {
#ifdef SYS_DEBUG
    printf("GPCDE Interrupt! GPC:0x%04x  GPD:0x%04x  GPE:0x%04x\n", u32GpcStatus, u32GpdStatus, u32GpeStatus);
#endif  //SYS_DEBUG
 
    /* Toggle LED (GPA7) */
    //outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->PIN) ^ (1 << 7));
#ifdef USE_KEY_QUEUE
	if (u32GpcStatus & (1)) {  //power_key
	  if (DrvTIMER_GetTicks(TMR2) <= Timeout_Screen_Saving)
        Put_key_Queue(Power_key);
	  DrvTIMER_ResetTicks(TMR2);
#ifdef SYS_DEBUG
	  printf("power_key current tick: %d\n", DrvTIMER_GetTicks(TMR2));
#endif  //SYS_DEBUG
    }
#else  //USE_KEY_QUEUE
      User_key = Power_key;
#endif  //USE_KEY_QUEUE
}

//PB.14/INT0 interrupt event callback
void EINT0Callback(void) {
#ifdef SYS_DEBUG
	printf("EXTINT0 Interrupt!: %d\n", extint0_count++);
#endif  //SYS_DEBUG
    
    /* Toggle LED (GPA7) */
    //outpw((uint32_t)&GPIOA->DOUT, inpw((uint32_t)&GPIOA->PIN) ^ (1 << 7));
#ifdef USE_KEY_QUEUE
	if (DrvTIMER_GetTicks(TMR2) <= Timeout_Screen_Saving)
      Put_key_Queue(Down_key);
    DrvTIMER_ResetTicks(TMR2);
#ifdef SYS_DEBUG
	printf("down_key current tick: %d\n", DrvTIMER_GetTicks(TMR2));
#endif  //SYS_DEBUG
#else  //USE_KEY_QUEUE
	User_key = Down_key;
#endif  //USE_KEY_QUEUE
}


#ifdef PRINTER_PORT
#define RXBUFSIZE 64
volatile uint8_t comRbuf[RXBUFSIZE];
volatile uint16_t comRbytes = 0;		/* Available receiving bytes */
volatile uint16_t comRhead 	= 0;
volatile uint16_t comRtail 	= 0;
void UART_INT_HANDLE(uint32_t u32IntStatus)
{
	uint8_t bInChar[1]={0xFF};
	

	if(u32IntStatus & DRVUART_RDAINT)
	{
		//printf("\nInput:");
		
		/* Get all the input characters */
#if PRINTER_PORT_ID==0
		while(UART0->ISR.RDA_IF==1)
#elif  PRINTER_PORT_ID==1
		while(UART1->ISR.RDA_IF==1)
#else
#endif
		{
			/* Get the character from UART Buffer */
			DrvUART_Read(PRINTER_PORT,bInChar,1);
            bPrinter_status = bInChar[0];
			printf("\n\rRDA_IF printer status: %x\n\r", bInChar[0]);
			
			/*if(bInChar[0] == '0')	
			{	
				g_bWait = FALSE;
			}*/
		
			/* Check if buffer full */
			if(comRbytes < RXBUFSIZE)
			{
				/* Enqueue the character */
				comRbuf[comRtail] = bInChar[0];
				comRtail = (comRtail == (RXBUFSIZE-1)) ? 0 : (comRtail+1);
				comRbytes++;
			}			
		}
		//printf("\nTransmission Test:");
	}
	else if(u32IntStatus & DRVUART_THREINT)
	{   
		   
        uint16_t tmp;
        tmp = comRtail;
			//bInChar[0] = comRbuf[comRhead];
			//DrvUART_Write(UART_PORT1,bInChar,1);
//printf("\nTransmission Test1:");
		if(comRhead != tmp)
		{
			bInChar[0] = comRbuf[comRhead];
  		    if (bInChar[0] < 128 && bInChar[0] >= 32) {
//#ifdef MaestroNano_Fit_Mode
			  DrvUART_Write(DEBUG_INFO_PORT,bInChar,1);
//#endif
			}
			else
				printf("\n\r THREIE status: %x\n\r", bInChar[0]);
			comRhead = (comRhead == (RXBUFSIZE-1)) ? 0 : (comRhead+1);
			comRbytes--;
		}
	}
}
#endif

/*20130516 added by michael
timer 0 callback*/
void TMR_Callback()
{
  refresh_time++;
}

/*20130604 added by michael
instead of polling USB events, we process USB events via interrupt
The USBD_IRQHandler linked to ARM interrupt vector table*/
void USBD_IRQHandler(void)
{
#if 1
	if (g_u8IsUsbPlugin && !(g_u8UsbState&USB_STATE_FLAG_SUSPENDED) && !g_u8IsPrepareFAT)
		Prepare_FAT();
#endif
	UsbIsr();
}

void TMR_Callback2()
{
  printf("TMR2\n");
}